package com.jinmdz.fmis.api.admin.service;


import com.jinmdz.fmis.api.admin.model.accountuser.*;
import com.jinmdz.fmis.api.api.model.common.IdVersionData;
import com.jinmdz.fmis.api.api.service.DictionaryService;
import com.jinmdz.fmis.api.base.BaseService;
import com.jinmdz.fmis.api.model.config.dictionary.OperationLogCode;
import com.jinmdz.fmis.api.model.system.UserItem;
import com.jinmdz.fmis.api.wrapper.DictionaryWrapper;
import com.jinmdz.fmis.api.wrapper.OperationWrapper;
import com.jinmdz.fmis.api.wrapper.SecurityWrapper;
import com.jinmdz.fmis.common.ext.StringBuilderExt;
import com.jinmdz.fmis.common.util.BeanUtil;
import com.jinmdz.fmis.common.util.DataUtil;
import com.jinmdz.fmis.core.base.BaseResult;
import com.jinmdz.fmis.core.constant.EDictCode;
import com.jinmdz.fmis.core.exception.ActionException;
import com.jinmdz.fmis.core.model.SearchLoadData;
import com.jinmdz.fmis.core.util.JacksonUtil;
import com.jinmdz.fmis.dao.admin.dao.AccountUserDao;
import com.jinmdz.fmis.dao.admin.dao.OrganizationDao;
import com.jinmdz.fmis.dao.admin.model.accountuser.AccountUserEditItem;
import com.jinmdz.fmis.dao.admin.model.accountuser.AccountUserListData;
import com.jinmdz.fmis.dao.admin.model.accountuser.AccountUserListItem;
import com.jinmdz.fmis.mapper.entity.SystemUserEntity;
import com.jinmdz.fmis.mapper.mapper.SystemUserMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;

/**
 * 员工账号Service
 *
 * @author LiCongLu
 * @date 2020-03-17 09:57
 */
@Service("accountUserService")
public class AccountUserService extends BaseService {

    @Resource
    private AccountUserDao accountUserDao;

    @Resource
    private DictionaryWrapper dictionaryWrapper;

    @Resource
    private SystemUserMapper systemUserMapper;

    @Resource
    private OperationWrapper operationWrapper;

    @Resource
    private OperationLogCode operationLogCode;

    @Resource
    private DictionaryService dictionaryService;

    @Resource
    private SecurityWrapper securityWrapper;

    @Resource
    private OrganizationDao organizationDao;

    /**
     * 加载员工账号信息
     *
     * @param data 查询条件
     * @author LiCongLu
     * @date 2020-03-17 09:53
     */
    public BaseResult<SearchLoadData<AccountUserListItem>> loadAccountUserList(AccountUserListData data) {
        startPageData(data);
        ArrayList<AccountUserListItem> loadItems = accountUserDao.listAccountUserList(data);
        // 设置字典文本
        dictionaryWrapper.resetDataText(loadItems);

        // 创建返回分页结果
        SearchLoadData<AccountUserListItem> loadData = getSearchLoadData(loadItems);
        return successData(loadData);
    }

    /**
     * 加载员工账号信息
     *
     * @param data 员工主键
     * @return
     * @author LiCongLu
     * @date 2020-03-17 09:54
     */
    public BaseResult<AccountUserLoadData> loadAccountUserWithId(AccountUserIdData data) {
        // 加载数据
        AccountUserLoadData loadData = new AccountUserLoadData();

        // 加载数据
        if (DataUtil.valid(data.getId())) {
            Integer loadId = data.getId();
            // 查询信息
            AccountUserEditItem loadItem = accountUserDao.getAccountUserEditById(loadId);
            if (DataUtil.isNull(loadItem) || DataUtil.isNull(loadItem.getId(), loadItem.getVersion())) {
                return failure("主键错误，不存在此员工账号信息");
            }
            loadData.setAccountUser(BeanUtil.copy2Bean(loadItem, new AccountUserSaveData()));
            loadData.getAccountUser().setLoginPassword("");
        }

        // 加载字典数据
        loadData.setDicts(dictionaryService.loadDictionaryMap(data.getDictTypeCodes()));

        // 加载所有组织机构
        loadData.setOrganizations(BeanUtil.copy2List(organizationDao.listOrganizationList(), AccountUserOrganizationItem.class));

        // 返回响应结果
        return successData(loadData);
    }

    /**
     * 保存员工账号信息
     *
     * @param userItem 当前帐号
     * @param data     请求数据
     * @return
     * @author LiCongLu
     * @date 2020-03-17 09:54
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult saveAccountUser(UserItem userItem, AccountUserSaveData data) throws ActionException {
        Integer id = data.getId();
        // 主键不为空
        if (DataUtil.valid(id)) {
            updateAccountUser(userItem, data);
        } else {
            id = insertAccountUser(userItem, data);
        }
        return success("保存成功");
    }

    /**
     * 插入员工账号信息
     *
     * @param userItem 当前帐号
     * @param data     请求数据
     * @return
     * @author LiCongLu
     * @date 2020-03-17 09:55
     */
    private Integer insertAccountUser(UserItem userItem, AccountUserSaveData data) throws ActionException {
        // 创建实体
        SystemUserEntity entity = getEntity(userItem, SystemUserEntity.class);

        // 设置登录帐号等信息
        insertLoginUserValue(data, entity);

        // 对员工信息进行判断处理
        checkAccountUserValue(entity);

        // 新增员工账号信息
        systemUserMapper.insertSystemUser(entity);
        // 判断保存员工信息结果
        if (DataUtil.invalid(entity.getId())) {
            throw exception("保存员工账号信息失败");
        }

        // 添加操作日志
        saveAccountUserLog(userItem, operationLogCode.getInsert(), data, null, entity);
        return entity.getId();
    }

    /**
     * 插入时验证处理登录帐号等信息
     *
     * @param data   请求数据
     * @param entity 员工账号信息
     * @return
     * @author LiCongLu
     * @date 2020-03-17 10:48
     */
    private void insertLoginUserValue(AccountUserSaveData data, SystemUserEntity entity) throws ActionException {
        // 记录请求时传来的登录帐号
        String savePassword = data.getLoginPassword();

        // 覆盖数据
        BeanUtil.copy2Bean(data, entity);

        // 清空登录信息，只有是登录帐号时才有效有用
        entity.setLoginUsername("")
                .setLoginPassword("")
                .setLoginSecretKey("");

        // 默认登录帐号为工号,默认为登录
        entity.setLoginUsername(data.getJobNo())
                .setAsLogin(1);

        // 判断登录帐号是否为空
        if (DataUtil.invalid(entity.getLoginUsername(), savePassword)) {
            throw exception("当员工是帐号时，登录帐号及密码不能为空！");
        }

        // 判断帐号登录的重复性
        Integer accountUserNoId = accountUserDao.getAccountUserIdByLoginUsername(entity.getId(), entity.getLoginUsername());
        if (DataUtil.valid(accountUserNoId)) {
            throw exception("存在重复的登录帐号");
        }

        // 创建秘密及密钥
        entity.setLoginSecretKey(securityWrapper.newSecretKey());
        entity.setLoginPassword(securityWrapper.getCipherText(savePassword, entity.getLoginSecretKey()));
    }

    /**
     * 验证处理员工信息
     *
     * @param entity 员工账号信息
     * @return
     * @author LiCongLu
     * @date 2020-03-17 10:48
     */
    private void checkAccountUserValue(SystemUserEntity entity) throws ActionException {

        // 判断禁用状态
        if (DataUtil.isNull(entity.getDisableState())) {
            entity.setDisableState(0);
        }

        // 判断排序值
        if (DataUtil.isNull(entity.getSort())) {
            entity.setSort(0);
        }

        // 判断员工编号的重复性
        Integer accountUserCodeId = accountUserDao.getAccountUserIdByJobNo(entity.getId(), entity.getJobNo());
        if (DataUtil.valid(accountUserCodeId)) {
            throw exception("存在重复的员工编号");
        }

        // 当是登录帐号且帐号不为空时，判断重复
        if (DataUtil.valid(entity.getAsLogin())) {
            // 判断登录帐号是否为空
            if (DataUtil.isNull(entity.getLoginUsername(), entity.getLoginPassword(), entity.getLoginSecretKey())) {
                throw exception("当员工是帐号时，登录帐号及密码不能为空！");
            }

            // 判断帐号登录的重复性
            Integer accountUserNoId = accountUserDao.getAccountUserIdByLoginUsername(entity.getId(), entity.getLoginUsername());
            if (DataUtil.valid(accountUserNoId)) {
                throw exception("存在重复的登录帐号");
            }
        }
    }

    /**
     * 添加员工修改记录
     *
     * @param userItem    当前帐号
     * @param logTypeCode 操作日志值
     * @param data        请求数据
     * @param oldValue    旧数据
     * @param entity      保存实体
     * @return
     * @author LiCongLu
     * @date 2020-03-17 10:02
     */
    private void saveAccountUserLog(UserItem userItem, Integer logTypeCode, AccountUserSaveData data, String oldValue, SystemUserEntity entity) throws ActionException {
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("保存员工账号信息，登录帐号[{0}]，员工编号[{1}]，姓名[{2}]，性别[{3}][{4}]，联系电话[{5}]，其他电话[{6}]，" +
                        " 联系地址[{7}]，所属公司外键[{8}]，所属公司外键[{9}]，禁用状态[{10}]，IC卡卡号[{11}]，备注[{12}]，操作人员[{13}]"
                , DataUtil.valid(entity.getAsLogin()) ? entity.getLoginUsername() : "非登录帐号", entity.getJobNo(), entity.getFullName()
                , String.valueOf(entity.getUserGenderCode()), dictionaryWrapper.getDataText(EDictCode.SEX_SIMPLE, entity.getUserGenderCode())
                , entity.getMobilePhone(), entity.getOtherPhone(), String.valueOf(entity.getCompanyId()), String.valueOf(entity.getDepartmentId())
                , String.valueOf(entity.getDisableState())
                , entity.getIcCardCode()
                , userItem.getFullName());

        // 添加日志
        operationWrapper.operationLog(userItem, logTypeCode, builder.toString(), JacksonUtil.obj2Json(data), oldValue, JacksonUtil.obj2Json(entity));
    }

    /**
     * 更新员工账号信息
     *
     * @param userItem 当前帐号
     * @param data     请求数据
     * @return
     * @author LiCongLu
     * @date 2020-03-17 10:13
     */
    private void updateAccountUser(UserItem userItem, AccountUserSaveData data) throws ActionException {
        // 验证主键和数据版本是否存在
        if (DataUtil.isNull(data.getId(), data.getVersion())) {
            throw exception("请求员工主键与员工版本号不能为空");
        }

        // 通过主键获取员工账号信息
        SystemUserEntity entity = systemUserMapper.getSystemUserById(data.getId());
        if (DataUtil.isNull(entity) || DataUtil.isNull(entity.getId(), entity.getVersion())) {
            throw exception("员工主键错误，不存在此员工信息");
        }

        // 验证信息版本
        if (!DataUtil.equals(data.getVersion(), entity.getVersion())) {
            throw exception(versionError("员工信息"));
        }

        // 记录旧数据
        String oldValue = JacksonUtil.obj2Json(entity);

        // 设置登录帐号等信息
        saveLoginUserValue(data, entity);

        // 对员工信息进行判断处理
        checkAccountUserValue(entity);

        // 更新员工账号信息
        systemUserMapper.updateSystemUser(entity);

        // 添加操作日志
        saveAccountUserLog(userItem, operationLogCode.getUpdate(), data, oldValue, entity);
    }

    /**
     * 更新时验证处理登录帐号等信息
     *
     * @param data   请求数据
     * @param entity 员工账号信息
     * @return
     * @author LiCongLu
     * @date 2020-03-17 10:49
     */
    private void saveLoginUserValue(AccountUserSaveData data, SystemUserEntity entity) throws ActionException {
        // 记录请求时传来的登录帐号
        String savePassword = data.getLoginPassword();

        // 记录原账号信息
        String loginPassword = entity.getLoginPassword();
        String loginSecretKey = entity.getLoginSecretKey();

        // 覆盖数据
        BeanUtil.copy2Bean(data, entity);

        // 清空登录信息，只有是登录帐号时才有效有用
        entity.setLoginPassword("")
                .setLoginSecretKey("");

        // 默认登录帐号为工号,默认为登录
        entity.setLoginUsername(data.getJobNo())
                .setAsLogin(1);

        // 判断帐号登录的重复性
        Integer accountUserNoId = accountUserDao.getAccountUserIdByLoginUsername(entity.getId(), entity.getLoginUsername());
        if (DataUtil.valid(accountUserNoId)) {
            throw exception("存在重复的登录帐号");
        }

        // 重新赋值就密码及密钥
        entity.setLoginPassword(loginPassword)
                .setLoginSecretKey(loginSecretKey);

        // 当新密码不为空时，更新密码及密钥
        if (DataUtil.valid(savePassword)) {
            entity.setLoginSecretKey(securityWrapper.newSecretKey());
            entity.setLoginPassword(securityWrapper.getCipherText(savePassword, entity.getLoginSecretKey()));
        }
    }

    /**
     * 删除指定id的员工账号信息记录
     *
     * @param userItem 当前帐号
     * @param data     主键和版本号
     * @return
     * @author LiCongLu
     * @date 2020-03-17 10:14
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult deleteAccountUserWithId(UserItem userItem, ArrayList<IdVersionData> data) throws ActionException {
        // 判断删除主键集合是否存在
        if (DataUtil.invalid(data)) {
            throw exception("不存在要删除的员工信息");
        }

        // 验证主键是否重复
        if (data.size() != getRepeatIdSize(data)) {
            throw exception("员工主键存在重复");
        }

        // 记录员工信息集合
        ArrayList<AccountUserEditItem> loadItems = new ArrayList<>();

        // 遍历查询进行删除
        for (IdVersionData idData : data) {
            // 通过主键查询员工信息
            AccountUserEditItem loadItem = accountUserDao.getAccountUserEditById(idData.getId());
            if (DataUtil.isNull(loadItem) || DataUtil.isNull(loadItem.getId(), loadItem.getVersion())) {
                throw exception("主键错误，不存在此员工信息");
            }

            // 验证员工信息版本
            if (!DataUtil.equals(loadItem.getVersion(), idData.getVersion())) {
                throw exception(versionError("员工信息"));
            }

            // 删除员工信息
            systemUserMapper.deletedForSystemUser(loadItem.getId(), userItem.getId(), loadItem.getVersion());
            // 记录员工信息
            loadItems.add(loadItem);
        }

        // 添加操作日志信息
        deleteAccountUserLog(userItem, operationLogCode.getDelete(), data, loadItems);

        return success("删除成功");
    }

    /**
     * 添加修改记录
     *
     * @param userItem    当前帐号
     * @param logTypeCode 操作日志值
     * @param data        请求数据
     * @param loadItems   删除信息实体
     * @return
     * @author LiCongLu
     * @date 2020-03-17 10:15
     */
    private void deleteAccountUserLog(UserItem userItem, Integer logTypeCode, ArrayList<IdVersionData> data, ArrayList<AccountUserEditItem> loadItems) throws ActionException {
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("删除员工账号信息，操作人员[{1}]", userItem.getFullName());
        // 添加日志
        operationWrapper.operationLog(userItem, logTypeCode, builder.toString(), JacksonUtil.obj2Json(data), JacksonUtil.obj2Json(loadItems), null);
    }

    /**
     * 根据员工部门id加载表【system_user】中保存的员工数据，用于机构树中加载员工信息
     *
     * @param data 部门主键
     * @return
     * @author LiCongLu
     * @date 2020-03-25 16:52
     */
    public BaseResult<ArrayList<AccountUserTreeItem>> loadAccountUserTreeWithDepartmentId(AccountDepartmentIdData data) {
        // 查询所有员工
        ArrayList<AccountUserEditItem> userItems = accountUserDao.listAccountUserEditByDepartmentId(data.getDepartmentId());
        ArrayList<AccountUserTreeItem> loadItems = new ArrayList<>();
        for (AccountUserEditItem userItem : userItems) {
            loadItems.add(new AccountUserTreeItem().setId(userItem.getId()).setLabel(userItem.getFullName()));
        }
        return successList(loadItems);
    }
}
